<template>
  <a-card title="楼房分户" style="width: 600px;pointer-events: all;">
    <template #extra>
      <UndoOutlined @click="refresh" />
    </template>
    <a-steps :current="currentStep" :items="steps">
    </a-steps>
    <div class="draw-area">
      <span>绘制户型:</span>
      <ForkOutlined class="icon-draw" @click="activeDraw" />
      <span>{{ textDraw }}</span>
    </div>
    <div class="form-area">
      <a-table size="small" bordered :data-source="buildingData" :columns="buildingColumns" :pagination="false">
        <template #bodyCell="{ column, text, record }">
          <template v-if="['posPrefix', 'unit'].includes(column.dataIndex)">
            <div>
              <a-input v-if="editableData[record.key]" v-model:value="editableData[record.key][column.dataIndex]"
                style="margin: -5px 0" />
              <template v-else>
                {{ text }}
              </template>
            </div>
          </template>

          <!-- 只有做区域绘制的时候，需要编辑 -->
          <template v-else-if="column.dataIndex === 'operation' && currentStep !== 2">
            <div class="editable-row-operations">
              <span v-if="editableData[record.key]" style="display: flex;justify-content: space-around;">
                <a-typography-link @click="save(record.key)">保存</a-typography-link>
                <a-popconfirm title="Sure to cancel?" @confirm="cancel(record.key)">
                  <a>取消</a>
                </a-popconfirm>
              </span>
              <span v-else>
                <a @click="edit(record.key)">编辑</a>
              </span>
            </div>
          </template>

          <!-- 只有户型切分的时候，需要定位 -->
          <template v-if="['positionFix'].includes(column.dataIndex)">
            <div @click="focusOnArea(record.key)">
              <img style="cursor: pointer;" width="20" height="20" src="/src/assets/position.png" alt="">
            </div>
          </template>
        </template>

      </a-table>
    </div>
    <!-- 楼房分层 -->
    <div class="floor-area" v-if="currentStep === 2 && showDivide">
      <span>最低点:</span>
      <a-input width="100" :value="minHeight" :min="-100" :max="200" :disabled="true"></a-input>
      <span>分割点:</span>
      <a-input width="100" :value="divideHeight" :min="-100" :max="200" :disabled="true"></a-input>
      <span>最高点:</span>
      <a-input width="100" :value="maxHeight" :min="-100" :max="200" :disabled="true"></a-input>
      <span>楼层数:</span>
      <a-input width="100" v-model:value="floorNum" :min="0" :max="100"></a-input>
    </div>
    <div class="button-area">
      <a-button v-if="currentStep < steps.length - 1" type="primary" @click="nextStep">下一步</a-button>
      <a-button v-if="showDivide" @click="divideFloor" style="margin:0 10px;">楼房分层</a-button>
      <a-button v-if="currentStep == steps.length - 1 && updateActive" type="primary" @click="updateInfo">
        生成数据
      </a-button>
    </div>
  </a-card>
</template>

<script setup>
import * as Cesium from 'cesium'
import { ref, reactive, computed, watch, onBeforeUnmount } from 'vue';
import { cloneDeep } from 'lodash'
import { binkEntityMaterial } from '@/cesiumTools/sceneManager.js'
import { changeCartesin3ToGeoJson, polygonCut, cartesian3ToDegreesHeight } from '@/cesiumTools/utils'
import DrawTool from '../cesiumTools/drawTool'
import { UndoOutlined, ForkOutlined } from '@ant-design/icons-vue'
import { useMapData } from '@/store'
import * as _ from 'lodash'
import { addHouse } from '@/api/api'
import { message } from 'ant-design-vue';

onBeforeUnmount(()=>{
  refresh()
})

const mapStore = useMapData()
const viewer = mapStore.Viewer
const drawTool = new DrawTool(viewer)
// 当前处于哪个步骤
const currentStep = ref(0)
// 展示楼房分层按钮的ui
const showDivide = ref(false)
// 控制显示最后生成按钮的ui
const updateActive = ref(false)
// 三个高度
const minHeight = ref(0)
const divideHeight = ref(0)
const maxHeight = ref(0)
// 楼层数
const floorNum = ref(0)

// 推送到服务端的数据
// polygonJson总区域geojson字符串
// polygonJsonArr切割后geojson字符串数组，如果没有切割，传[]
// unitArr 单位数组
// heightArr 三个高度数组
// name 楼栋名称
// floorNum楼层数
const postDataSource = {
  polygonJson: '',
  polygonJsonArr: [],
  unitArr: [],
  heightArr: [],
  name: '',
  floorNum: 0
}
// 户型设置
const buildingData = ref([])
const buildingColumns = ref([{
  title: '分户坐标',
  dataIndex: 'position',
  align: 'center',
  width: '30%',
  ellipsis: true
}, {
  title: '地址前缀',
  dataIndex: 'posPrefix',
  align: 'center',
  width: '30%',
  ellipsis: true
}, {
  title: '单位',
  dataIndex: 'unit',
  align: 'center'
}, {
  title: '操作',
  dataIndex: 'operation',
  align: 'center'
}])

const steps = ref([
  {
    title: '区域绘制',
    key: '区域绘制'
  }, {
    title: '户型切分',
    key: '户型切分'
  }, {
    title: '楼房分层',
    key: '楼房分层'
  }
])

watch(currentStep, (val) => {
  if (val === 0) {
    if (!buildingColumns.value.find(item => item.dataIndex === 'operation')) {
      buildingColumns.value.push({
        title: '操作',
        dataIndex: 'operation',
        align: 'center'
      })
    }
  }
  if (val === 1) {
    if (!buildingColumns.value.find(item => item.dataIndex === 'positionFix')) {
      buildingColumns.value.push({
        title: '定位',
        dataIndex: 'positionFix',
        align: 'center',
        width: '10%'
      })
    }
  }
  // 楼房分层，将后面两列删除
  if (val === 2) {
    buildingColumns.value = buildingColumns.value.filter(item => item.dataIndex !== 'positionFix' && item.dataIndex !== 'operation')
  }
})

const textDraw = computed(() => {
  let res = ''
  switch (currentStep.value) {
    case 0:
      res = '绘制图形'
      break;
    case 1:
      res = '户型裁剪'
      break;
    case 2:
      res = '楼层分层'
      break;
    default:
      break;
  }
  return res
})

const editableData = reactive({});
// 可编辑表格配置
const edit = key => {
    editableData[key] = cloneDeep(buildingData.value.filter(item => key === item.key)[0]);
};
const save = key => {
    Object.assign(buildingData.value.filter(item => key === item.key)[0], editableData[key]);
    delete editableData[key];
};
const cancel = key => {
    delete editableData[key];
};

const nextStep=()=>{
  if(buildingData.value.length){
    currentStep.value++
  }else{
    message.warn('请先绘制区域')
  }
}

// 上传服务
const updateInfo=async ()=>{
  postDataSource.unitArr=buildingData.value.map(item=>Number(item.unit))
  const heightArr=[minHeight.value,divideHeight.value,maxHeight.value]
  postDataSource.heightArr=heightArr
  postDataSource.name=buildingData.value[0].posPrefix
  postDataSource.floorNum=Number(floorNum.value)
  const res=await addHouse(postDataSource)
  if(res.code===200){
    refresh()
    message.success('分户成功')
  }else{
    message.error('分户失败,请检查参数')
  }
}

// 处理实体闪烁
const focusOnArea=(key)=>{
  const targetEnt=viewer.entities.values.find(item=>item.key==key)
  if(targetEnt){
    binkEntityMaterial(targetEnt)
  }
}

// 清除所有的实体和primitive
const refresh = () => {
  if (primPrimitives.length) {
    primPrimitives.forEach(item => {
      viewer.scene.primitives.remove(item)
    })
    primPrimitives.length = 0
  }
  viewer.entities.removeAll()
  currentStep.value = 0
  buildingData.value = []
  minHeight.value=0
  divideHeight.value=0
  maxHeight.value=0
  postDataSource = {
    polygonJson: '',
    polygonJsonArr: [],
    unitArr: [],
    heightArr: [],
    name: '',
    floorNum: 0
  }
}

// 楼房分层
const primPrimitives=[]
const divideFloor=()=>{
  if(floorNum.value){
    viewer.entities.removeAll()
    // 计算每一层楼的高度
    const itemHeight=(maxHeight.value-divideHeight.value)/(floorNum.value-1)
    buildingData.value.forEach(unit=>{
      const {position}=unit
      // 多边形需要polygonHieracrchy,height,extrudedHeight
      const positionPolygon=position.split(',').map(item=>Number(item))
      const polygonHierarchy=new Cesium.PolygonHierarchy(new Cesium.Cartesian3.fromDegreesArray(positionPolygon))
      for(let i=0;i<floorNum.value;i++){
        let height,extrudedHeight
        if(i===0){
          height=minHeight.value
          extrudedHeight=divideHeight.value
        }else{
          height=divideHeight.value+(i-1)*itemHeight
          extrudedHeight=divideHeight.value+(i)*itemHeight
        }
        const geometryInstance=new Cesium.GeometryInstance({
          geometry:new Cesium.PolygonGeometry({
            polygonHierarchy:polygonHierarchy,
            height,
            extrudedHeight
          }),
          attributes : {
            color : Cesium.ColorGeometryInstanceAttribute.fromColor(
              Cesium.Color.fromRandom({alpha:0.3})
            )
          }
        })
        const primitive=new Cesium.ClassificationPrimitive({
          geometryInstances:geometryInstance,
          classificationType:Cesium.ClassificationType.CESIUM_3D_TILE
        })
        primPrimitives.push(primitive)
        viewer.scene.primitives.add(primitive)
      }
    })
    updateActive.value=true
  }
}

let drawEndEvent
let lastEnt
const activeDraw=()=>{
  // 步骤1：框选出楼栋
  if(currentStep.value===0){
    drawTool.active(drawTool.DrawTypes.Polygon)
    drawEndEvent=(ent,positions)=>{
      const {geojson,positionLng}=changeCartesin3ToGeoJson(positions,'polygon')
      if(!_.isEmpty(geojson)){
        // 将geojson设置到服务端数据源
        postDataSource.polygonJson=JSON.stringify(geojson)
        // 将表格中的数据填充
        buildingData.value[0]={
          position:positionLng.join(','),
          posPrefix:'xxx小区xxx楼栋',
          unit:'1'
        }
      }
      lastEnt=ent
      drawTool.removeListener(drawEndEvent)
      drawEndEvent=null
    }
    drawTool.DrawEndEvent.addEventListener(drawEndEvent)
  }else if(currentStep.value===1){
    // 第二个步骤，将上一步的geojson进行裁剪，裁剪为多个geojson
    drawTool.active(drawTool.DrawTypes.Polyline)
    drawEndEvent=(ent,positions)=>{
      const {geojson:lineJson}=changeCartesin3ToGeoJson(positions,'polyline')
      const polygonJson=JSON.parse(postDataSource.polygonJson)
      const polygonCollection=polygonCut(polygonJson,lineJson)
      if(!_.isEmpty(polygonCollection)){
        // 将上一个步骤中绘制的实体清除
        drawTool.removeAllDrawEnts()
        viewer.entities.remove(lastEnt)
        lastEnt=null
        // 处理要传入的服务的数据
        postDataSource.polygonJsonArr=polygonCollection.features.map((item,index)=>{
          return JSON.stringify(item.geometry)
        })

        // 处理实体加载
        Cesium.GeoJsonDataSource.load(polygonCollection,{clampToGround:true}).then(info=>{
          const tableData=[]
          info.entities.values.forEach((item,index)=>{
            tableData.push({
              key:index,
              position:polygonCollection.features[index].geometry.coordinates.toString(),
              posPrefix:buildingData.value[0].posPrefix,
              unit:index+1
            })
            // 将索引放到实体数据中
            item.key=index
            item.polygon.material=new Cesium.Color.fromRandom({alpha:0.6})
            viewer.entities.add(item)
          })
          buildingData.value=tableData
        })
      }
      
      drawTool.removeListener(drawEndEvent)
      drawEndEvent=null
    }
    drawTool.DrawEndEvent.addEventListener(drawEndEvent)
  }else if(currentStep.value===2){
    drawTool.active(drawTool.DrawTypes.Point)
    drawEndEvent=(ent,positions)=>{
      // 只有点击三个点，才能进行分户
      if(positions.length===3){
        const heights=positions.map(position=>{
          const positionLng=cartesian3ToDegreesHeight(position)
          return positionLng[2]
        })
        heights.sort((a,b)=>a-b)
        minHeight.value=heights[0]
        divideHeight.value=heights[1]
        maxHeight.value=heights[2]
        showDivide.value=true
      }else{
        message.warn('请点击底层，二楼以及顶层三个位置的点')
      }

      drawTool.removeListener(drawEndEvent)
      drawEndEvent=null
    }
    drawTool.DrawEndEvent.addEventListener(drawEndEvent)
  }
}

</script>

<style scoped>
.button-area {
  display: flex;
  justify-content: flex-end;
  margin-top: 20px;
}

.draw-area {
  margin: 20px 0;
}

.draw-area span {
  margin: 0 4px;
}

.icon-draw {
  padding: 4px;
}

.icon-draw:hover {
  cursor: pointer;
  background-color: skyblue;
  color: #fff;
}

.floor-area span {
  margin: 0 10px;
}
</style>